/**
 * Copyright Notice
 */
package com.gtd.account.user

import javax.jdo.Query
import javax.jdo.PersistenceManager

import com.google.appengine.api.datastore.Key
import com.google.appengine.api.datastore.KeyFactory

import com.gtd.*
import com.gtd.jdo.*
import com.gtd.util.CryptoUtil
import com.gtd.account.*
import com.gtd.account.contactInfo.ContactInfoService

class UserService implements IUserService {
	def data
	def message
  def code
  private final String CODE_INVALID_PARAMS = "userservice.invalid-params"
  private final String CODE_CAN_NOT_MAKE_PERSISTENT = "userservice.can-not-make-persistent"
  private final String CODE_INVALID_USERNAME = "userservice.invalid-username"
  private final String CODE_CREATE_USERNAME_SUCCESS = "userservice.create-username-success"
  private final String CODE_EXISTED_USERNAME = "userservice.existed-username"
  private final String CODE_EXISTED_EMAIL = "userservice.existed-email"
  private final String CODE_AUTHENTICATE_SUCCESS = "userservice.authenticate-success"
  private final String CODE_AUTHENTICATE_FAIL = "userservice.authenticate-fail"
  private final String CODE_DELETE_SUCCESS = "userservice.delete-success"
  private final String CODE_DELETE_FAIL = "userservice.delete-fail"
  private final String CODE_USER_DELETED = "userservice.user-deleted"

  private final String MSG_INVALID_PARAMS = "Invalid Params."
  private final String MSG_CAN_NOT_MAKE_PERSISTENT = "Account can not be made persistent."
  private final String MSG_INVALID_USERNAME = "Invalid username."
  private final String MSG_CREATED_USERNAME_SUCCESS = "Username created successful."
  private final String MSG_EXISTED_USERNAME = "This username has existed."
  private final String MSG_EXISTED_EMAIL = "This email has already registered."
  private final String MSG_AUTHENTICATE_SUCCESS = "Authenticate successful."
  private final String MSG_AUTHENTICATE_FAIL = "Authenticate failed."
  private final String MSG_DELETE_SUCCESS = "Delete account successfully."
  private final String MSG_DELETE_FAIL = "Deleted user failed."
  private final String MSG_USER_DELETED = "Account was deleted."

	def UserService() {

	}


	def getDefinition() {

	}

	def getPresent(o) {
    // Get contactGroups, accountSettings id
    def oContactGroups = new ArrayList()
    def oAccountSettings = new ArrayList()

    o.contactGroups.each({
        oContactGroups.add(it.key.id)
      })

    o.accountSettings.each({
        oAccountSettings.add(it.key.id)
      })
    // Get contactInfo
    def oEmailAddresses = new ArrayList()
    def oLocalAddresses = new ArrayList()
    def oPhoneNumbers = new ArrayList()
    def oContactInfo

    if (o.contactInfo != null) {
      o.contactInfo.emailAddresses.each({
          oEmailAddresses.add(it.key.id)
        })
      o.contactInfo.localAddresses.each({
          oLocalAddresses.add(it.key.id)
        })
      o.contactInfo.phoneNumbers.each({
          oPhoneNumbers.add(it.key.id)
        })

      oContactInfo = [
        fullName: o.contactInfo.fullName,
        nickname: o.contactInfo.nickname,
        emailAddresses: oEmailAddresses,
        localAddresses: oLocalAddresses,
        phoneNumbers: oPhoneNumbers
      ]
    } else {
      oContactInfo = ""
    }

		def oUser = [
      id: o.key.id,
      username: o.username,
      email: o.email,
      active: o.active,
      registeredDate: o.registeredDate,
      role: o.role,
      avatarUri: o.avatarUri,
      contactInfo: oContactInfo,
      contactGroups: oContactGroups,
      accountSettings: oAccountSettings
    ]
    return data = [user: oUser]
	}

	def getListPresent(oList) {
		def list = new ArrayList()
		oList.each({
        list.add(getPresent(it))
      })

		data = [
      users: list
    ]
	}

  /**
   * Get all users
   */
	def get() {
    PersistenceManager pm = JdoUtil.getPersistenceManager()
    Query query = pm.newQuery(User.class)
    List<User> users = query.execute()
    return users
	}

	def get(id) {

	}

	def get(page, itemsPerPage) {

	}

	def save(u) {

	}
  /*
   * delete user means set deleted = true.
   * Not really delete object from datastore.
   * To permanently delete object from datastore, call remove()
   */
	def delete(id) {
    Key k = KeyFactory.createKey(User.class.simpleName, id)
    try {
      User user = JdoUtil.getObjectById(User.class, k)
      //Set deleted = true
      //Checking if deleted
      if (user.deleted) {
        //Do nothing and return deleted warning
        code = CODE_USER_DELETED
        message = MSG_USER_DELETED
        return false
      } else {
        // Set deleted = true and makePersistent
        user.deleted = true
      }
      if (JdoUtil.makePersistent(user)) {
        code = CODE_DELETE_SUCCESS
        message = MSG_DELETE_SUCCESS
        return true
      }
    } catch(Exception e) {
      code = CODE_DELETE_FAIL
      message = MSG_DELETE_FAIL
    }
    return false
	}

	def existed(u) {
    //TODO: Check existing status by username + email
  }

	def encryptPassword(pwd) {
    return CryptoUtil.encrypt(pwd)
	}

  private isValidUsername(username) {
    //TODO: Validate more
    if (!username) return false
    if (username == "" || username.length() < 2) return false
    return true
  }

  private existedUsername(username) {
    PersistenceManager pm = JdoUtil.getPersistenceManager()
    Query query = pm.newQuery(User.class)
    query.setFilter("username == usernameParam")
    query.declareParameters("String usernameParam")
    //System.out.println("UserService - existedUsername: " + query.toString())
    try {
      List<User> results = query.execute(username)
      if (results.iterator().hasNext()) {
        return true
      }
    } catch(Exception e) {
      //TODO: Log.warn
    } finally {
      query.closeAll()
    }
    return false
  }

  private existedEmail(email) {
    PersistenceManager pm = JdoUtil.getPersistenceManager()
    Query query = pm.newQuery(User.class)
    query.setFilter("email == emailParam")
    query.declareParameters("String emailParam")
    try {
      List<User> results = query.execute(email)
      if (results.iterator().hasNext()) {
        return true
      }
    } catch(Exception e) {
      //TODO: log.warn
    } finally {
      query.closeAll()
    }
    return false
  }


	def authenticate(params) {
    def username = params.username
    def password = encryptPassword(params.password)
    /*
    //TODO: Do we need to check this? Instead, we need to check username + password
    // to prevent attack. => Return CODE_INVALID_PARAMS
    if (!isValidUsername(username)) {
    code = CODE_INVALID_USERNAME
    message = MSG_INVALID_USERNAME
    return false
    }*/
    PersistenceManager pm = JdoUtil.getPersistenceManager()
    Query query = pm.newQuery(User.class)
    query.setFilter("username == usernameParam && password == passwordParam")
    query.declareParameters("String usernameParam, String passwordParam")
    //System.out.println("UserService - authenticate: " + query.toString())
    try {
      List<User> results = (List<User>) query.execute(username, password)
      //System.out.println(results)
      if (results.iterator().hasNext()) {
        for (User u : results) {
          data = getPresent(u)
        }
        code = CODE_AUTHENTICATE_SUCCESS
        message = MSG_AUTHENTICATE_SUCCESS
        return true
      } else {
        code = CODE_AUTHENTICATE_FAIL
        message = MSG_AUTHENTICATE_FAIL
        return false
      }
    } catch(Exception e) {
      message = e.getMessage()
      return false
    } finally {
      query.closeAll()
    }

    
	}

	def authorize(user, resouce) {

	}

	/**
	 * Create user object
	 * @param params
	 * @return object data if created
	 *         false if not created
	 * @since  1.0
	 */
	def create(params) {
    //Invalid params checking
    if (!(params.username || params.email || params.password)) {
      code = CODE_INVALID_PARAMS
      message = MSG_INVALID_PARAMS
      return false
    }
    params.registeredDate = System.currentTimeMillis()
    params.password = encryptPassword(params.password)
    if (!isValidUsername(params.username)) {
      code = CODE_INVALID_USERNAME
      message = MSG_INVALID_USERNAME
      return false
    }
    if (existedUsername(params.username)) {
      code = CODE_EXISTED_USERNAME
      message = MSG_EXISTED_USERNAME
      return false
    }

    if (existedEmail(params.email)) {
      code = CODE_EXISTED_EMAIL
      message = MSG_EXISTED_EMAIL
      return false
    }
		def user = new User(params)
    //def contactInfoService = new ContactInfoService()
    //def contactInfo = contactInfoService.getInstance(params)
    //if (contactInfo) {
    //user.contactInfo = contactInfo
    //}
    if (user.validate()) {
      try {
        data = JdoUtil.makePersistent(user)
        code = CODE_CREATE_USERNAME_SUCCESS
        message = MSG_CREATED_USERNAME_SUCCESS
        return true
      } catch(Exception e) {
        //message = e.getMessage()
        code = CODE_CAN_NOT_MAKE_PERSISTENT
        message = MSG_CAN_NOT_MAKE_PERSISTENT
      }
    } else {
      code = CODE_INVALID_PARAMS
      message = MSG_INVALID_PARAMS
    }
    return false
	}
}